
#pragma once

namespace scheduler_basic {

    // 以下都是给定时调度器用的时钟源

    struct SysTickMsSource {
        inline static auto get_time() {
            return clock_ms();
        }

        using TimeType = uint32_t;
    };


    struct SysTickUsSource {
        inline static auto get_time() {
            return clock_us();
        }

        using TimeType = uint32_t;
    };


    struct SysTickTicksSource {
        inline static auto get_time() {
            return clock_ticks();
        }

        using TimeType = uint32_t;
    };


    /**
     * @brief 不依赖中断的微秒延时函数，可在中断服务函数中使用，要保证SysTick 处于运行状态
     *
     * 依赖SysTick->VAL 进行计时，所以单次延时不能超过SysTick 溢出周期；
     * 默认SysTick 中断周期是10ms，此时单次最多延时10ms，对于中断函数内的延时而言应该完全足够了。
     * 
     * TODO: 考虑实现一个基于DWT 的版本，除了CORTEX M0 不支持，其他单片机上DWT 都比Systick 更好使
     *
     */
    class FastUsCycle {
       private:
        uint32_t _last_ticks = 0;
        uint32_t _duration_ticks = 0;

       public:
        FastUsCycle() :
            _last_ticks(clock_ticks()) {}

        /**
         * @brief 一个延时周期的最大长度
         *
         * @return uint32_t
         */
        static uint32_t max_us() {
            return SYS_TICK_CYCLE_N_MS * 1000;
        }

        static uint32_t ticks_from_us(uint32_t us) {
            return us_to_ticks(us);
        }

        /**
         * @brief 阻塞延时，最大延时不能超过一个SysTick 周期
         *
         * @param us
         */
        static void delay_us(uint32_t us) {
            uint32_t duration = us_to_ticks(us);

            if (duration > max_us()) {
                // TODO: 延时值过大，报错
                return;
            }

            uint32_t start_ticks = clock_ticks();
            while ((clock_ticks() - start_ticks) < duration);
        }


        bool set_duration(uint32_t us) {
            // TODO: 延时值过大，报错
            uint32_t t = us_to_ticks(us);
            if (t > max_us()) {
                _duration_ticks = 0;
                return false;
            }
            else {
                _duration_ticks = t;
                return true;
            }
        }


        void reset() {
            _last_ticks = clock_ticks();
        }


        bool delay() {
            return (clock_ticks() - _last_ticks) > _duration_ticks;
        }


        bool cycle() {
            if (delay()) {
                reset();
                return true;
            }
            return false;
        }

        /**
         * @brief 从上次reset 后经过的微秒数
         * 
         * @return uint32_t 
         */
        uint32_t us_since_reset() {
            auto ticks = clock_ticks() - _last_ticks;
            return ticks_to_us(ticks);
        }
    };
    
}